1 module targets.windows;
2 
3 import features.hipreme_engine;
4 import features.ldc;
5 
6 version(Windows):
7 import commons;
8 import feature;
9 import features.msvclinker;
10 import features.vcruntime140;
11 import std.windows.registry;
12 static import std.file;
13 
14 
15 bool hasVCRuntime140()
16 {
17 	string arch = "X64";
18 	version(Win32) arch = "X32";
19 	Key currKey = windowsGetKeyWithPath("SOFTWARE", "WOW6432Node", "Microsoft", "VisualStudio", "14.0", "VC", "Runtimes", arch);
20 	return currKey.getValue("Installed").value_DWORD == 1;
21 }
22 
23 bool hasMSVCLinker()
24 {
25 	import common_windows;
26 	immutable supportedPre2017Versions = ["14.0"];
27 	
28 	if(detectVSInstallDirViaCOM())
29 		return true;
30 
31 	if(Key k = windowsGetKeyWithPath("SOFTWARE", "Microsoft", "VisualStudio", "SxS", "VS7"))
32 	if(k.getValue("15.0").value_SZ)
33 		return true;
34 	
35 	foreach (ver; supportedPre2017Versions)
36 	{
37 		Key k = windowsGetKeyWithPath("SOFTWARE", "Microsoft", "VisualStudio", ver);
38 		try
39 		{
40 			if(k !is null && k.getValue("InstallDir"))
41 				return true;
42 		}
43 		catch(Exception e){return false;}
44 	}
45 	return false;
46 }
47 
48 private string getVCDownloadLink()
49 {
50 	version(Win64) return "https://aka.ms/vs/17/release/vc_redist.x64.exe";
51 	else version(Win32) return "https://aka.ms/vs/17/release/vc_redist.x86.exe";
52 	else version(AArch64) return "https://aka.ms/vs/17/release/vc_redist.arm64.exe";
53 }
54 
55 private bool installVCRuntime140(ref Terminal t, ref RealTimeConsoleInput input)
56 {
57 	string vcredist = buildNormalizedPath(std.file.getcwd(), "buildtools", "vcredist.exe");
58 	if(!downloadFileIfNotExists("Get Microsoft Visual C++ Redistributable for being able to compile D Programming Language", getVCDownloadLink, vcredist, t, input))
59 	{
60 		t.writelnError("Needs to download VCRuntime.");
61 		return false;
62 	}
63 	t.writelnHighlighted("Installing Microsoft Visual C++ Redistributable");
64 
65 	auto ret = t.wait(spawnShell(vcredist~" /install /quiet /norestart")) == 0;
66 	if(ret)
67 		t.writelnSuccess("Successfully installed Microsoft Visual C++ Redistributable.");
68 	else 
69 		t.writelnError("Could not install Microsoft Visual C++ Redistributable.");
70 	return ret;
71 }
72 
73 private bool installMSLinker(ref Terminal t, ref RealTimeConsoleInput input)
74 {
75 	import features.vs_buildtools_installer;
76 
77 	return installFromVSBuildTools.execute(t, input, "Get Windows SDK for being able  to compile D programming language",
78 	[
79 		"Microsoft.VisualStudio.Workload.VCTools",
80 		"Microsoft.VisualStudio.Component.TestTools.BuildTools",
81 		"Microsoft.VisualStudio.Component.VC.ASAN",
82 		"Microsoft.VisualStudio.Component.VC.Tools.x86.x64"
83 	]);
84 }
85 
86 ChoiceResult prepareWindows(Choice* c, ref Terminal t, ref RealTimeConsoleInput input, in CompilationOptions cOpts)
87 {
88 	if(!hasVCRuntime140)
89 	{
90 		if(!installVCRuntime140(t, input))
91 		{
92 			t.writelnError("Your system must install Microsoft Visual C++ 14 for using the D Programming Language.");
93 			return ChoiceResult.Error;
94 		}
95 	}
96 	if(!hasMSVCLinker)
97 	{
98 		if(!installMSLinker(t, input))
99 		{
100 			if(hasMSVCLinker)
101 				t.writelnSuccess("Succesfully installed Windows SDK.");
102 			else
103 			{
104 				t.writelnError("Could not install Windows SDK.");
105 				return ChoiceResult.Error;
106 			}
107 		}
108 		else
109 		{
110 			t.writelnError("Your system must install the MSLinker. This is important for creating binaries without dependencies.");
111 			return ChoiceResult.Error;
112 		}
113 	}
114 
115 	// waitOperations([{
116 		std.file.chdir(configs["gamePath"].str);
117 		if(timed(t, waitDub(t, DubArguments().command("build").configuration("script").opts(cOpts)) != 0))
118 			return ChoiceResult.Error;
119 			// return false;
120 		// return true;
121 	// },
122 	// {
123 		if(!c.scriptOnly)
124 		{
125 			std.file.chdir(getHipPath);
126 			if(timed(t, waitDub(t, DubArguments().command("build").configuration("script").opts(cOpts))) != 0)
127 				return ChoiceResult.Error;
128 		}
129 		// return true;
130 	// }]);
131 	t.wait(spawnShell((getHipPath("bin", "desktop", "hipreme_engine.exe") ~ " "~ configs["gamePath"].str)));
132 
133 	return ChoiceResult.None;
134 }